package com.komeri.komeriapl;

import static com.komeri.komeriapl.Constants.*;

import java.util.Collection;
import java.util.HashSet;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import com.google.zxing.ResultPoint;

/**
 * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
 * transparency outside it, as well as the laser scanner animation and result points.
 * カメラからJANコードを取る時のレイアウト
 * @author Liu Mingjia
 */
public final class ViewfinderView extends View {

  private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
  private static final long ANIMATION_DELAY = 100L;
  private static final int OPAQUE = 0xFF;
  private final Paint paint;
  private final Paint laserPaint;
  private Bitmap resultBitmap;
  private final int maskColor;
  private final int resultColor;
  private final int frameColor;
  private final int laserColor;
  private final int resultPointColor;
  private int scannerAlpha;
  private Collection<ResultPoint> possibleResultPoints;
  private Collection<ResultPoint> lastPossibleResultPoints;
  private BarCodeType barCodeType;

  // This constructor is used when the class is built from an XML resource.
  public ViewfinderView(Context context, AttributeSet attrs) {
    super(context, attrs);

    // Initialize these once for performance rather than calling them every time in onDraw().
    paint = new Paint();
    laserPaint = new Paint();
    Resources resources = getResources();
    maskColor = resources.getColor(R.color.viewfinder_mask);
    resultColor = resources.getColor(R.color.result_view);
    frameColor = resources.getColor(R.color.viewfinder_frame);
    laserColor = resources.getColor(R.color.viewfinder_laser);
    resultPointColor = resources.getColor(R.color.possible_result_points);
    scannerAlpha = 0;
    possibleResultPoints = new HashSet<ResultPoint>(5);
    
	if (context instanceof BarCodeCaptureActivity) {
		barCodeType = BarCodeType.BARCODE;
	}
	else if (context instanceof QrCodeCaptureActivity) {
		barCodeType = BarCodeType.QRCODE;
	}
  }

  @SuppressLint("DrawAllocation")
  @Override
  public void onDraw(Canvas canvas) {
    Rect frame = CameraManager.get().getFramingRect();
    if (frame == null) {
      return;
    }
    int width = canvas.getWidth();
    int height = canvas.getHeight();

    // Draw the exterior (i.e. outside the framing rect) darkened
    paint.setColor(resultBitmap != null ? resultColor : maskColor);
    canvas.drawRect(0, 0, width, frame.top, paint);
    canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
    canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
    canvas.drawRect(0, frame.bottom + 1, width, height, paint);

    if (resultBitmap != null) {
      // Draw the opaque result bitmap over the scanning rectangle
      paint.setAlpha(OPAQUE);
      canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
    } else {

      // Draw a two pixel solid black border inside the framing rect
      paint.setColor(frameColor);
      canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
      canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
      canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
      canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);

      // Draw a red "laser scanner" line through the middle to show decoding is active
      laserPaint.setColor(laserColor);
      laserPaint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
      scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;

      //barCodeTypeにより、スキャンガイドを変更する
      switch (barCodeType) {
	      case BARCODE:

		      int middle = frame.height() / 2 + frame.top;
		      canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, laserPaint);
		      
		      break;
		      
	      case QRCODE:
		      Path path = new Path();
		      
		      Resources res = getContext().getResources();
	    	  int marginPx = (int) res.getDimension(R.dimen.qr_scan_guide_margin);
	    	  int lengthPx = (int) res.getDimension(R.dimen.qr_scan_guide_length);
	    	  
	    	  //左上のガイド
		      path.moveTo(frame.left + marginPx, frame.top + marginPx);
		      path.lineTo(frame.left + marginPx, frame.top + lengthPx);
		      path.moveTo(frame.left + marginPx, frame.top + marginPx);
		      path.lineTo(frame.left + lengthPx, frame.top + marginPx);
		      
	    	  //左下のガイド
		      path.moveTo(frame.left + marginPx, frame.bottom - marginPx);
		      path.lineTo(frame.left + marginPx, frame.bottom - lengthPx);
		      path.moveTo(frame.left + marginPx, frame.bottom - marginPx);
		      path.lineTo(frame.left + lengthPx, frame.bottom - marginPx);
		      
	    	  //右上のガイド
		      path.moveTo(frame.right - marginPx, frame.top + marginPx);
		      path.lineTo(frame.right - marginPx, frame.top + lengthPx);
		      path.moveTo(frame.right - marginPx, frame.top + marginPx);
		      path.lineTo(frame.right - lengthPx, frame.top + marginPx);
		      
	    	  //右下のガイド
		      path.moveTo(frame.right - marginPx, frame.bottom - marginPx);
		      path.lineTo(frame.right - marginPx, frame.bottom - lengthPx);
		      path.moveTo(frame.right - marginPx, frame.bottom - marginPx);
		      path.lineTo(frame.right - lengthPx, frame.bottom - marginPx);
		      
		      laserPaint.setStyle(Paint.Style.STROKE);
		      laserPaint.setStrokeWidth(3.0f);
		      canvas.drawPath(path, laserPaint);
		      
		      break;
		      
	      default:
      }  
      
      Collection<ResultPoint> currentPossible = possibleResultPoints;
      Collection<ResultPoint> currentLast = lastPossibleResultPoints;
      
      if (currentPossible.isEmpty()) {
        lastPossibleResultPoints = null;
      } else {
        possibleResultPoints = new HashSet<ResultPoint>(5);
        lastPossibleResultPoints = currentPossible;
        paint.setAlpha(OPAQUE);
        paint.setColor(resultPointColor);
        for (ResultPoint point : currentPossible) {
          canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
        }
      }
      
      if (currentLast != null) {
    	  
          paint.setAlpha(OPAQUE / 2);
        
          paint.setColor(resultPointColor);
        
          for (ResultPoint point : currentLast) {
        	
              canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
          }
      }

      // Request another update at the animation interval, but only repaint the laser line,
      // not the entire viewfinder mask.
      postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
    }
  }

  /**
   * パーシャルリフレッシュ
   * */
  public void drawViewfinder() {
	  
    resultBitmap = null;
    
    invalidate();
  }

  /**
   * Draw a bitmap with the result points highlighted instead of the live scanning display.
   *
   * @param barcode An image of the decoded barcode.
   */
  public void drawResultBitmap(Bitmap barcode) {
    resultBitmap = barcode;
    invalidate();
  }

  public void addPossibleResultPoint(ResultPoint point) {
    possibleResultPoints.add(point);
  }

}
